/* 
* Copyright (c) 2021 Talkweb Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License. 
*/

#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "lwip/sockets.h"
#include "wifi_connect.h"

#include "beep_demo.h"
#include "light_demo.h"
#include "infrared_demo.h"

#include<sys/types.h>
#include<sys/select.h>
#include<netinet/in.h>

/*TCP SERVER 参数*/
#define _PROT_ 8800
#define _SERVER_IP_ "192.168.0.102"
#define TCP_BACKLOG 5
#define IP_LEN 16

/*wifi参数配置*/
#define WIFI_SSID "230A"
#define WIFI_PASSWORD "230230230"

/*接收缓存和数据*/
char recvbuf[1460];
char *udpSendBuf = "Hello! I'm Talkweb UDP Server!";

#define TASK_STACK_SIZE 1024
#define TASK_PRIO 25

const unsigned char rgbDutyLow[] = {20,4,20};  //低亮度
const unsigned char rgbDutyHig[] = {99,99,99}; //高亮度


/*UDP服务器任务，采用select*/
static void UDPServerTaskWithSelect(void)
{
	enum ENV_BODY_STATE  envBodyState = BODY_NOT;   //记录人体状态变量
    enum ENV_LIGHT_STATE envLightState = LIGHT_DAY; //记录环境光照变量   

    //蜂鸣器初始化
    BeepInit();

    //红外传感器初始化
    InfraredSensorInit();

    //三色灯初始化
    TricolorLightInit();

	//服务端地址信息
	struct sockaddr_in server_sock;
	
	int sin_size = sizeof(struct sockaddr_in);
	//连接Wifi
	if(WifiConnect(WIFI_SSID,WIFI_PASSWORD)!=0)
	{
		perror("Wifi connect error!");
		exit(1);
	}
	//in_addr_t localIpaddr = GetLocalIpaddr();
	uint32_t localIpaddr = htonl(GetLocalIpaddr());
	char strr[IP_LEN];
	inet_ntop(AF_INET, &server_sock.sin_addr, strr, sizeof(strr));
	printf("GetLocalIpaddr is %s \n",strr);

	//创建socket
	printf("socket begin\n");
	int sock_fd=-1;
	if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
	{
		perror("socket is error\r\n");
		exit(1);
	}
	printf("sock_fd=%d\n",sock_fd);

	bzero(&server_sock, sizeof(server_sock));
	server_sock.sin_family = AF_INET;
	//server_sock.sin_addr.s_addr = htonl(INADDR_ANY);
	inet_pton(AF_INET, _SERVER_IP_, &server_sock.sin_addr); //inet_addr("127.0.0.1");
	server_sock.sin_port = htons(_PROT_);
	char str[IP_LEN];
	inet_ntop(AF_INET, &server_sock.sin_addr, str, sizeof(str));
	printf("udp server IP_addr: %s at PORT %d\n",str,ntohs(server_sock.sin_port));
	
	//调用bind函数绑定socket和地址
	if (bind(sock_fd, (struct sockaddr *)&server_sock, sizeof(struct sockaddr)) == -1)
	{
		perror("bind is error\r\n");
		exit(1);
	}
	
	fd_set fds;
	FD_ZERO(&fds);	

	while(true)
	{	
		//更新当前环境红外人体状态
        envBodyState = GetEnvBodyState();
        
        if(envBodyState == BODY_COME || envBodyState == BODY_KEEP) {
        	if(envBodyState == BODY_COME)
		   	{
		        BeepStart();
	            osDelay(100);
	            BeepStop();
		    }
        	//更新当前环境光照状态
        	envLightState = GetEnvLightState();

        	printf("select wait...\n");
			FD_SET(sock_fd,&fds);
	        int ret = select(sock_fd + 1, &fds, NULL, NULL, NULL);
			if(ret<=0)
			{
				//超时等
				printf("[DISCOVERY]ret:%d\n", ret);
				continue;
			}
			if(FD_ISSET(sock_fd,&fds))
			{
				//客户端地址信息
				struct sockaddr_in repaddr;
				memset(recvbuf,0,sizeof(recvbuf));
				memset(&repaddr, 0, sizeof(struct sockaddr));
				int res = recvfrom(sock_fd, recvbuf, sizeof(recvbuf)-1, 0, (struct sockaddr *)&repaddr, (socklen_t *)&sin_size);
				//"exit"特殊字符串，表示客户端申请断开链接
				if(strlen(recvbuf)==4 && memcmp(recvbuf,"exit",5)==0)
				{
					printf("remote client close,msg is %s\n",recvbuf);
					sendto(sock_fd, "exit", strlen("exit") + 1, 0, (struct sockaddr *)&repaddr, (socklen_t)sin_size);
				}
				else
				{
					printf("recv msg :%s\n",recvbuf);
					if (sendto(sock_fd, udpSendBuf, strlen(udpSendBuf) + 1, 0, (struct sockaddr *)&repaddr, (socklen_t)sin_size) == -1)
					{
						perror("send error \r\n");
					}
					else{ printf("send msg %s \n",udpSendBuf);}

			        if (strcmp(recvbuf, "SITTING") == 0) {
			        	printf("in sitting\n");
		        		if(envLightState == LIGHT_DUSK)
			            {
			            	printf("in dusk\n");
			                TricolorLightStart(rgbDutyLow[0], rgbDutyLow[1], rgbDutyLow[2]);
			            }
			            else if(envLightState == LIGHT_NIGHT)
			            {
			            	printf("in night\n");
			                TricolorLightStart(rgbDutyHig[0], rgbDutyHig[1], rgbDutyHig[2]);  
			            }
		        	} 
		        	else if (strcmp(recvbuf, "STANDING UP") == 0)
		        	{
		        		TricolorLightStop();
		        	}
				}
				osDelay(10);
				FD_ZERO(&fds);
			}
        }
        //有人离开时蜂鸣器响, RGB灯熄灭
        else if(envBodyState == BODY_LEAVE)
        {
            TricolorLightStop();
            BeepStart();
            osDelay(100);
            BeepStop();
        }
	}

	close(sock_fd);
	FD_CLR(sock_fd,&fds);
	sock_fd=-1;
	return ;
}

static void UDPServerDemo(void)
{
	osThreadAttr_t attr;

	attr.name = "UDPServerTask";
	attr.attr_bits = 0U;
	attr.cb_mem = NULL;
	attr.cb_size = 0U;
	attr.stack_mem = NULL;
	attr.stack_size = 1024*4;
	attr.priority = osPriorityNormal;

	if (osThreadNew((osThreadFunc_t)UDPServerTaskWithSelect, NULL, &attr) == NULL)
	{
		printf("[UDPServerDemo] Falied to create UDPServerTask!\n");
	}
}

APP_FEATURE_INIT(UDPServerDemo);